// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module  crc_calculate
(
    input   wire            I_sclk,
    input   wire            I_rst_n,
    //input
    input   wire            I_net_en,
    input   wire    [ 7: 0] I_net_data,
    //output
    output  reg             O_net_en,
    output  reg     [ 7: 0] O_net_data
);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam  HEAD_BYTES = 8;

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  [ 11: 0] byte_cnt;
reg  [ 9: 0] net_en_dly;
reg  crc_en;
reg  data_en;
reg  invert_en;
reg  [ 7: 0] din;
wire [ 31: 0] crc32_value;
wire [ 7: 0] crc32_out;
reg  [ 7: 0] net_data_dly1;
reg  [ 7: 0] net_data_dly2;
reg  [ 7: 0] net_data_dly3;
reg  [ 7: 0] net_data_dly4;
reg  [ 7: 0] net_data_dly5;

/******************************************************************************
                              <module body>
******************************************************************************/
assign crc32_out = {crc32_value[24],
                    crc32_value[25],
                    crc32_value[26],
                    crc32_value[27],
                    crc32_value[28],
                    crc32_value[29],
                    crc32_value[30],
                    crc32_value[31]};

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        byte_cnt <= 'd0;
    else if (!I_net_en)
        byte_cnt <= 'd0;
    else
        byte_cnt <= byte_cnt + 1;

crc32_d8_01 u_crc32_d8_01(
    .sclk(I_sclk),
    .crc_en(crc_en),
    .data_en(data_en),
    .invert_en(invert_en),
    .din(din),

    .crc32_value(crc32_value)
);

always @(posedge I_sclk)
    if (I_net_en)
        din <= I_net_data;
    else
        din <= 8'hFF;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        net_en_dly <= 'd0;
    else
        net_en_dly <= {net_en_dly[8:0],I_net_en};

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        crc_en <= 1'b0;
    else
        crc_en <= I_net_en || (net_en_dly[3:0] != 'd0);

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        data_en <= 1'b0;
    else if (byte_cnt == HEAD_BYTES)
        data_en <= 1'b1;
    else if (net_en_dly[4] && !net_en_dly[3])
        data_en <= 1'b0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        invert_en <= 1'b0;
    else
        invert_en <= (byte_cnt >= 8) && (byte_cnt < 8 + 4);

always @(posedge I_sclk)
    begin
    net_data_dly1 <= I_net_data;
    net_data_dly2 <= net_data_dly1;
    net_data_dly3 <= net_data_dly2;
    net_data_dly4 <= net_data_dly3;
    net_data_dly5 <= net_data_dly4;
    end

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_data <= 'd0;
    else if (net_en_dly[8] && !net_en_dly[4])
        O_net_data <= crc32_out;
    else
        O_net_data <= net_data_dly5;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_en <= 1'b0;
    else if (!net_en_dly[5] && net_en_dly[4])
        O_net_en <= 1'b1;
    else if (net_en_dly[9] && !net_en_dly[8])
        O_net_en <= 1'b0;

endmodule
`default_nettype wire

